package com.atguigu.springcloud.config;

import com.atguigu.springcloud.common.ThreadLocalProxyHolder;
import com.atguigu.springcloud.extend.RedisService;


import com.atguigu.springcloud.user.AuthContants;
import com.atguigu.springcloud.user.impl.AuthClientUserImpl;
import lombok.AllArgsConstructor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;


/**
 * @author xiaolong
 * @version 1.0
 * @description: 过滤器的设置
 * @date 2021/10/19 8:42
 */
@Configuration
@ConditionalOnProperty(name = "gosuncn.auth.client.chenck.enable", havingValue = "true", matchIfMissing = true)
public class AuthFilterConfig {

    @Autowired
    private RedisService service;

    @Value("${gosuncn.response.webHeader:G-Rpc}")
    private String rpcHeader;

    //通过方法完成对Filter组件的注册
    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        //定义自己的过滤器
        registrationBean.setFilter(new MyFilter(service, rpcHeader));
        //因为filter比bean先加载，也就是spring会先加载filter指定的类到container中，这样filter中注入的spring bean就为null了。
        //指明作用于filter的所有生命周期。为True，则spring来管理Filter.init()和Filter.destroy()；若为false，则这两个方法失效！！
        registrationBean.addInitParameter("targetFilterLifecycle", "true");

        registrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico");
        //配置过滤规则
        registrationBean.addUrlPatterns("/*");
        //request
        registrationBean.setDispatcherTypes(DispatcherType.REQUEST);
        return registrationBean;
    }


}

//实现过滤器
@AllArgsConstructor
class MyFilter implements Filter {

    private static final Logger log = LoggerFactory.getLogger("api_log");

    private final RedisService service;

    private final String rpcHeader;


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void destroy() {

    }

    //拦截的方法都会进入dofilter方法
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String header = httpRequest.getHeader(AuthContants.REQUEST_ID);
        if (header == null) {
            header = httpRequest.getHeader(rpcHeader);
        }
        String requestURI = httpRequest.getRequestURI();
        log.info("request[{}] {}", header, requestURI);
        try {
            String gAuth = httpRequest.getHeader(AuthContants.AUTH_PASS);
            if (gAuth != null) {
                gAuth = URLDecoder.decode(gAuth, Charset.defaultCharset().name());
            }
            String token = httpRequest.getHeader(AuthContants.TOKEN_HEADER);
            if (!StringUtils.hasText(token)) {
                token = "token" + httpRequest.getHeader(AuthContants.TOKEN);
            }
            AuthClientUserImpl user = new AuthClientUserImpl(gAuth, token, service);
            //将代理对象存入ThreadLocal  （项目启动springboot会加载bean，会在starterConfiguration中的iSystemUser方法创建bean）
            ThreadLocalProxyHolder.set(user);
            chain.doFilter(request, response);
        } finally {
            int status = ((HttpServletResponse) response).getStatus();
            if (HttpStatus.valueOf(status) == HttpStatus.OK) {
                log.info("response[{}] {}", header, requestURI);
            } else {
                log.error("response[{}] {} status ={}", header, requestURI, status);
            }
            //当一次请求完成立马删除代理对象
            ThreadLocalProxyHolder.remove();
        }
    }
}
